<template>
  <div class="reservation-container">
    <!-- 头部区域 -->
    <div class="header">
      <div class="title-and-selector">
        <span class="main-title">预约资源</span>
        <el-select
          v-model="selectedDeviceId"
          placeholder="请选择设备"
          filterable
          style="width: 240px; margin-left: 20px"
        >
          <el-option
            v-for="device in filteredDeviceList"
            :key="device.id ?? 'all'"
            :label="device.name"
            :value="device.id"
          />
        </el-select>
      </div>
      <div class="date-navigator">
        <h2>{{ weekRange }}</h2>
        <el-icon class="nav-arrow" @click="prevWeek"><ArrowLeftBold /></el-icon>
        <span class="week-tag" :class="{ 'is-current-week': weekRelativeText === '本周' }">{{
          weekRelativeText
        }}</span>
        <el-icon class="nav-arrow" @click="nextWeek"><ArrowRightBold /></el-icon>
      </div>
    </div>

    <!-- 日历主体 -->
    <div v-loading="isLoading" class="calendar-wrapper">
      <!-- 日历头部 -->
      <div class="calendar-header" :style="{ paddingRight: scrollbarWidth + 'px' }">
        <div class="header-corner"></div>
        <div
          v-for="day in weekDays"
          :key="day.fullDate"
          class="header-cell"
          :class="{ 'is-today': day.isToday }"
        >
          <span class="day-of-week">{{ day.dayOfWeek }}</span>
          <span class="date-of-month">{{ day.date }}</span>
        </div>
      </div>

      <!-- 日历滚动区域 -->
      <div class="calendar-scroll-container" ref="scrollContainerRef">
        <div class="calendar-grid">
          <!-- 时间轴 -->
          <div class="time-axis">
            <div
              v-for="slot in timeSlots"
              :key="slot.time"
              class="time-slot-label"
              :data-time="slot.label"
            ></div>
          </div>
          <!-- 预约区域 -->
          <div class="schedule-area">
            <div
              v-for="day in weekDays"
              :key="day.fullDate"
              class="day-column"
              :class="{ 'is-today': day.isToday }"
            >
              <div v-for="n in 24" :key="n" class="hour-grid-block"></div>
              <div class="day-content">
                <template v-if="processedBookingsByDay.has(day.fullDate)">
                  <el-popover
                    v-for="booking in processedBookingsByDay.get(day.fullDate)"
                    :key="booking.segmentKey"
                    placement="right-start"
                    :width="320"
                    trigger="hover"
                    popper-class="booking-popover"
                  >
                    <template #default>
                      <div class="popover-content">
                        <p><strong>姓名:</strong> {{ booking.originalBooking.contact_name }}</p>
                        <p>
                          <strong>联系电话:</strong> {{ booking.originalBooking.contact_phone }}
                        </p>
                        <p><strong>课题组:</strong> {{ booking.originalBooking.contact_group }}</p>
                        <p><strong>预约设备:</strong> {{ booking.originalBooking.device.name }}</p>
                        <p>
                          <strong>开始时间:</strong>
                          {{ dayjs(booking.originalBooking.start_time).format('YYYY-MM-DD HH:mm') }}
                        </p>
                        <p>
                          <strong>结束时间:</strong>
                          {{ dayjs(booking.originalBooking.end_time).format('YYYY-MM-DD HH:mm') }}
                        </p>
                      </div>
                    </template>
                    <template #reference>
                      <div
                        class="booking-item booked"
                        :style="{
                          top: booking.top + 'px',
                          height: booking.height + 'px',
                          width: booking.width + '%',
                          left: booking.left + '%',
                        }"
                      >
                        <div class="booking-info">
                          <strong :title="booking.originalBooking.device.name">{{
                            booking.originalBooking.device.name
                          }}</strong>
                          <span>{{ booking.originalBooking.contact_name }}</span>
                        </div>
                      </div>
                    </template>
                  </el-popover>
                </template>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="legend">
      <span><i class="box available"></i> 可预约</span>
      <span><i class="box booked"></i> 已预约</span>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onBeforeUnmount, watch } from 'vue'
import dayjs from 'dayjs'
import 'dayjs/locale/zh-cn'
import weekOfYear from 'dayjs/plugin/weekOfYear'
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'
import { ElMessage } from 'element-plus'
import { ArrowLeftBold, ArrowRightBold } from '@element-plus/icons-vue'

// 确保这里的导入路径与您的项目结构一致
import { getAllDevicesApi, getReservationListApi } from '@/api'
import type { Device } from '@/api/types/device'
import type { ReservationDetail, ReservationListParams } from '@/api/types/reservation'

dayjs.locale('zh-cn')
dayjs.extend(weekOfYear)
dayjs.extend(isSameOrAfter)
dayjs.extend(isSameOrBefore)

// --- 核心配置 ---
const HOUR_HEIGHT_PX = 80
const PIXELS_PER_MINUTE = HOUR_HEIGHT_PX / 60

// --- 响应式状态 ---
const isLoading = ref(true)
const allDevices = ref<Device[]>([])
const reservations = ref<ReservationDetail[]>([])
const selectedDeviceId = ref<number | null>(null)
const currentWeekStart = ref(dayjs().startOf('week'))

// --- 水平对齐修复 ---
const scrollContainerRef = ref<HTMLElement | null>(null)
const scrollbarWidth = ref(0)
let resizeObserver: ResizeObserver | null = null

const updateScrollbarWidth = () => {
  if (scrollContainerRef.value) {
    scrollbarWidth.value =
      scrollContainerRef.value.offsetWidth - scrollContainerRef.value.clientWidth
  }
}

onMounted(() => {
  fetchDataForWeek()
  if (scrollContainerRef.value) {
    resizeObserver = new ResizeObserver(updateScrollbarWidth)
    resizeObserver.observe(scrollContainerRef.value)
  }
})

onBeforeUnmount(() => {
  if (resizeObserver && scrollContainerRef.value) {
    resizeObserver.unobserve(scrollContainerRef.value)
  }
})

// --- API 调用 ---
const fetchDataForWeek = async () => {
  isLoading.value = true
  try {
    const startDate = currentWeekStart.value.format('YYYY-MM-DD')
    const endDate = currentWeekStart.value.add(6, 'day').format('YYYY-MM-DD')

    const params: ReservationListParams = {
      page: 1,
      size: 9999, // 使用 `size` 并设置一个足够大的值来获取全部数据
      start_date: startDate,
      end_date: endDate,
      status: 'confirmed',
    }

    const [devicesRes, reservationsRes] = await Promise.all([
      getAllDevicesApi(),
      getReservationListApi(params),
    ])

    allDevices.value = devicesRes
    reservations.value = reservationsRes.items || []
  } catch (error) {
    ElMessage.error('获取周数据失败')
    console.error(error)
  } finally {
    isLoading.value = false
  }
}

// --- 计算属性 ---

// **新增：计算周的相对文本**
const weekRelativeText = computed(() => {
  const todayWeekStart = dayjs().startOf('week')
  const diff = currentWeekStart.value.diff(todayWeekStart, 'week')

  if (diff === 0) return '本周'
  if (diff === -1) return '上一周'
  if (diff === 1) return '下一周'
  if (diff < 0) return `前 ${-diff} 周`
  return `后 ${diff} 周`
})

const filteredDeviceList = computed(() => {
  const deviceIdsInReservations = new Set(reservations.value.map((r) => r.device.id))
  const activeDevices = allDevices.value.filter((d) => deviceIdsInReservations.has(d.id))
  return [{ id: null, name: '全部设备' }, ...activeDevices]
})

interface ProcessedSegment {
  segmentKey: string
  top: number
  height: number
  width: number
  left: number
  originalBooking: ReservationDetail
}

const doesOverlap = (
  b1: { start: dayjs.Dayjs; end: dayjs.Dayjs },
  b2: { start: dayjs.Dayjs; end: dayjs.Dayjs },
): boolean => {
  return b1.start.isBefore(b2.end) && b2.start.isBefore(b1.end)
}

const processedBookingsByDay = computed(() => {
  const finalMap = new Map<string, ProcessedSegment[]>()
  const visibleReservations =
    selectedDeviceId.value === null
      ? reservations.value
      : reservations.value.filter((r) => r.device.id === selectedDeviceId.value)

  const segments: Array<{
    dayKey: string
    start: dayjs.Dayjs
    end: dayjs.Dayjs
    originalBooking: ReservationDetail
  }> = []
  for (const booking of visibleReservations) {
    let start = dayjs(booking.start_time)
    const end = dayjs(booking.end_time)
    let current = start
    while (current.isBefore(end)) {
      const endOfDay = current.endOf('day')
      const segmentEnd = end.isBefore(endOfDay) ? end : endOfDay
      segments.push({
        dayKey: current.format('YYYY-MM-DD'),
        start: current,
        end: segmentEnd,
        originalBooking: booking,
      })
      current = current.add(1, 'day').startOf('day')
    }
  }

  const segmentsByDay = new Map<string, typeof segments>()
  for (const segment of segments) {
    if (!segmentsByDay.has(segment.dayKey)) segmentsByDay.set(segment.dayKey, [])
    segmentsByDay.get(segment.dayKey)!.push(segment)
  }

  for (const [dayKey, daySegments] of segmentsByDay.entries()) {
    const processedDaySegments: ProcessedSegment[] = []
    for (const segment of daySegments) {
      const contemporaries = daySegments.filter((peer) => doesOverlap(segment, peer))
      contemporaries.sort((a, b) => a.originalBooking.id - b.originalBooking.id)

      const totalColumns = contemporaries.length
      const columnIndex = contemporaries.findIndex(
        (p) => p.originalBooking.id === segment.originalBooking.id,
      )

      const width = 100 / totalColumns
      const left = columnIndex * width

      const minutesFromDayStart = segment.start.diff(segment.start.startOf('day'), 'minute')
      const durationInMinutes = Math.max(segment.end.diff(segment.start, 'minute'), 1)

      const top = minutesFromDayStart * PIXELS_PER_MINUTE
      const height = Math.max(durationInMinutes * PIXELS_PER_MINUTE, 20)

      processedDaySegments.push({
        segmentKey: `${segment.originalBooking.id}-${dayKey}`,
        top,
        height,
        width,
        left,
        originalBooking: segment.originalBooking,
      })
    }
    finalMap.set(dayKey, processedDaySegments)
  }

  return finalMap
})

const timeSlots = computed(() => {
  const slots = []
  for (let h = 0; h < 24; h++) {
    slots.push({ time: `${h}:00`, label: `${h.toString().padStart(2, '0')}:00` })
  }
  return slots
})

const weekDays = computed(() => {
  const today = dayjs()
  const days = []
  const weekDayMap = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
  for (let i = 0; i < 7; i++) {
    const day = currentWeekStart.value.add(i, 'day')
    days.push({
      dayOfWeek: weekDayMap[day.day()],
      date: day.format('MM/DD'),
      fullDate: day.format('YYYY-MM-DD'),
      isToday: day.isSame(today, 'day'),
    })
  }
  return days
})

const weekRange = computed(() => {
  const start = currentWeekStart.value.format('YYYY.MM.DD')
  const end = currentWeekStart.value.add(6, 'day').format('YYYY.MM.DD')
  return `${start} — ${end}`
})

// --- 方法 ---
const prevWeek = () => {
  currentWeekStart.value = currentWeekStart.value.subtract(7, 'day')
  fetchDataForWeek()
}
const nextWeek = () => {
  currentWeekStart.value = currentWeekStart.value.add(7, 'day')
  fetchDataForWeek()
}
</script>

<style>
/* ... (全局 Popover 样式不变) ... */
.booking-popover {
  background-color: #303133 !important;
  color: #fff !important;
  border: none !important;
  border-radius: 4px;
}
.booking-popover.el-popper .el-popper__arrow::before {
  background: #303133 !important;
  border: none !important;
}
.popover-content p {
  margin: 8px 0;
}
</style>

<!-- **最终优化的样式** -->
<style scoped>
/* 整体容器 */
.reservation-container {
  padding: 24px;
  background-color: #fff;
  font-family:
    'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial,
    sans-serif;
}

/* 头部样式 */
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}
.main-title {
  color: #303133;
  font-size: 22px;
  font-weight: 600;
}
.title-and-selector {
  display: flex;
  align-items: center;
}
.date-navigator {
  display: flex;
  align-items: center;
  gap: 15px;
}
.date-navigator h2 {
  font-size: 20px;
  color: #2b77e0;
  margin: 0;
  font-weight: 500;
}
.nav-arrow {
  cursor: pointer;
  color: #909399;
  font-size: 16px;
  transition: color 0.3s;
}
.nav-arrow:hover {
  color: #2b77e0;
}
/* **样式修改：周标签的通用和特定样式** */
.week-tag {
  background-color: #f0f2f5;
  padding: 4px 10px;
  border-radius: 4px;
  color: #606266;
  font-size: 14px;
}
.week-tag.is-current-week {
  background-color: #ecf5ff;
  color: #409eff;
  font-weight: 500;
}

/* 日历主体框架 */
.calendar-wrapper {
  border: 1px solid #e4e7ed;
  border-radius: 4px;
}
.calendar-header {
  display: flex;
  background-color: #4d6486;
  border-bottom: 1px solid #4d6486;
}
.header-corner {
  flex: 0 0 80px;
  border-right: 1px solid #4d6486;
}
.header-cell {
  flex: 1;
  text-align: center;
  padding: 10px 0;
  border-left: 1px solid #4d6486;
  transition: background-color 0.3s;
}
.header-cell:first-child {
  border-left: none;
}
.header-cell .day-of-week {
  font-size: 14px;
  font-weight: 500;
  color: #ffffff;
}
.header-cell .date-of-month {
  font-size: 12px;
  color: #fafbfc;
  margin-left: 8px;
}
/* **样式新增：当天高亮** */
.header-cell.is-today {
  background-color: #2e3337;
}

/* 滚动容器 */
.calendar-scroll-container {
  position: relative;
  height: 600px;
  overflow: auto;
}
.calendar-grid {
  display: flex;
  min-width: 1000px;
}

/* 时间轴 */
.time-axis {
  flex: 0 0 80px;
  background-color: #4d6486;
  position: sticky;
  left: 0;
  z-index: 20;
}
.time-slot-label {
  height: v-bind(HOUR_HEIGHT_PX + 'px');
  text-align: center;
  color: #ffffff;
  font-size: 12px;
  position: relative;
  box-sizing: border-box;
}
.time-slot-label::after {
  content: attr(data-time);
  position: absolute;
  top: 0;
  transform: translateY(-50%);
  left: 50%;
  transform: translateX(-50%);
  background: #4d6486;
  padding: 0 4px;
}
.time-slot-label:first-child::after {
  content: '';
}

/* 预约区域 */
.schedule-area {
  display: flex;
  flex: 1;
}
.day-column {
  flex: 1;
  position: relative;
  border-left: 1px dotted #0e0c0c;
  transition: background-color 0.3s;
}
.day-column:first-child {
  border-left: none;
}
/* **样式新增：当天高亮** */
.day-column.is-today {
  background-color: #ffffff;
}

/* **样式修改：使用 ::before 伪元素画出半小时的虚线** */
.hour-grid-block {
  height: v-bind(HOUR_HEIGHT_PX + 'px');
  border-bottom: 1px solid #eeada1; /* 整点实线 */
  box-sizing: border-box;
  position: relative;
}
.hour-grid-block::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  border-top: 1px dotted #eeada1; /* 半点虚线 */
}

.day-content {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}

/* 预约块样式 */
.booking-item {
  position: absolute;
  border-radius: 4px;
  padding: 4px 6px;
  box-sizing: border-box;
  overflow: hidden;
  transition: all 0.2s ease;
  cursor: pointer;
  z-index: 5;
}
.booking-item:hover {
  z-index: 6;
  transform: scale(1.01);
  box-shadow: 0 4px 12px rgba(35, 25, 25, 0.15);
}
.booking-info {
  display: flex;
  flex-direction: column;
  font-size: 12px;
  line-height: 1.4;
}
.booking-info strong {
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.booking-item.booked {
  background-color: #fef0f0;
  border: 1px solid #eda2a2;
  border-left: 3px solid #f90000;
  color: #6c2f26f0;
}

/* 图例 */
.legend {
  margin-top: 20px;
  display: flex;
  gap: 24px;
  font-size: 14px;
  color: #606266;
  align-items: center;
}
.legend .box {
  display: inline-block;
  width: 14px;
  height: 14px;
  margin-right: 8px;
  vertical-align: middle;
  border: 1px solid #1e2430;
  border-radius: 2px;
}
.legend .available {
  background-color: #fff;
}
.legend .booked {
  background-color: #e44141;
}
</style>
